//By Francois Budin
#ifndef Matrix_cxx
#define Matrix_cxx


#include "Matrix.h"

namespace FPTK
{
	template<class T>
    Matrix<T>::Matrix(long _R,long _C):TabND<T>(2,_R,_C)
	{
	}

	template<class T>
   Matrix<T>::~Matrix()
	{
	}


//template<class T> template<class C>
//Matrix<C> Matrix<T>::template Cast()
//{
//Matrix<C> tmp(GetSizeDim(0),GetSizeDim(1));
//for(long i=0;i<GetSizeDim(0);i++)
//{
//   for(long j=0;j<GetSizeDim(1);j++)
//   {
//   tmp.SetElement((int)GetElement(i,j),i,j);
//   }
//}
//return tmp;
//}

template<class T> template<class C>
Matrix<T>::operator Matrix<C> const() const
{
   Matrix<C> tmp(GetSizeDim(0),GetSizeDim(1));
for(long i=0;i<GetSizeDim(0);i++)
{
   for(long j=0;j<GetSizeDim(1);j++)
   {
   tmp.SetElement((C)GetElement(i,j),i,j);
   }
}
return tmp;
}



template<class T>
Matrix<T> Matrix<T>::operator+(const Matrix<T>& m2) const
{
   Matrix<T> tmp(SizeDim[0],SizeDim[1]);
   Exception ex("Matrix::operator+","Matrices have different sizes");
   if(m2.GetSizeDim(0)!=SizeDim[0] || m2.GetSizeDim(1)!=SizeDim[1]) throw ex;
   for(int i=0;i<SizeDim[0];i++)
   {
      for(int j=0;j<SizeDim[1];j++)
      {
          tmp.SetElement(GetElement(i,j)+m2.GetElement(i,j),i,j);
      }
   }
   return tmp;
}




template<class T>
void Matrix<T>::SetId()
{
   if(SizeDim[1]!=SizeDim[0])
   {
       Exception ex("Matrix::SetId","Not a square matrix");
       throw ex;
   }
   Zeros();
   for(int i=0;i<SizeDim[0];i++)
   {
      SetElement(T(1),i,i);
   }
}




template<class T>
Matrix<T> Matrix<T>::operator*(const Matrix<T>& m2) const
{
   Matrix<T> tmp(SizeDim[0],m2.GetSizeDim(1));
   tmp.Zeros();
   Exception ex("Matrix::operator*","Matrices don't have the good size");
   if(SizeDim[1]!=m2.GetSizeDim(0)) throw ex;
   for(int i=0;i<SizeDim[0];i++)
   {
       for(int j=0;j<m2.GetSizeDim(1);j++)
       {
           for(int k=0;k<SizeDim[1];k++)
           {
               tmp.SetElement(tmp.GetElement(i,j)+GetElement(i,k)*m2.GetElement(k,j),i,j);
           }
       }
   }
   return tmp;
}

template<class T>
Vector<T> Matrix<T>::operator*(const Vector<T>& v) const
{
Exception ex("The Matrix::operator*","Matrix must have the same number of column than the Vector has row");
if(GetSizeDim(1)!=v.GetSizeDim(0)) throw ex;
Matrix<T> tmp(GetSizeDim(0),1);
tmp.SetVector(0,v);
tmp=*(this)*tmp;
return tmp.GetVector(0);

}

template<class T>
Vector<T> Matrix<T>::GetVector(long c) const
{
   Exception ex("The Matrix::GetVector","The Vector is outside the Matrix");
   if(GetSizeDim(1)<=c) throw ex;
   Vector<T> tmp(SizeDim[0]);
   for(int i=0;i<SizeDim[0];i++)
   {
      tmp.SetElement(GetElement(i,c),i);
   }
   return tmp;
}


template<class T> template<class S>
Matrix<T> Matrix<T>::operator*(S f) const
{
   Matrix<T> tmp(SizeDim[0],SizeDim[1]);
   for(int i=0;i<SizeDim[0];i++)
   {
      for(int j=0;j<SizeDim[1];j++)
      {
         tmp.SetElement(GetElement(i,j)*(T)f,i,j);
      }
   }
   return tmp;
}

template<class T>
void Matrix<T>::SetAllVector(long nb,Vector<T> *v1,...)
{
   try
   {
      Exception ex2("The Matrix::SetAllVector","The Vector doesn\'t have the good size");
      Exception ex("The Matrix::SetAllVector","Not the good number of vector");
      Exception ex3("The Matrix::SetAllVector","Some of the Vectors don't have the good type");
      if(nb!=GetSizeDim(1)) throw ex;
      va_list ap;
      const Vector<T>** listvector=new const Vector<T>*[GetSizeDim(1)];
      va_start(ap,nb);
      for(int i=0;i<nb;i++)
      {
         listvector[i] =( va_arg(ap,Vector<T>*));
         //va_arg(ap,const Vector<T>);
      }
      va_end(ap);
      for(long i=0;i<GetSizeDim(1);i++)
      {
         if(listvector[i]->GetType()!=typeid(T).name()) throw ex3;
         if(GetSizeDim(0)!=listvector[i]->GetSizeDim(0)) throw ex2;
         for(int j=0;j<listvector[i]->GetSizeDim(0);j++)
         {
            SetElement(listvector[i]->GetElement(j),j,i);
         }
      }
      delete []listvector;
   }
   catch(std::bad_alloc &ba)
   {
      Exception ex4("TabND::Constructor:",ba.what());
      throw ex4;
   }
}


template<class T>
void Matrix<T>::SetVector(long c,const Vector<T>& v)
{
   Exception ex("The Matrix::SetVector","The Vector is outside the Matrix");
   if(GetSizeDim(1)<=c) throw ex;
   for(long i=0;i<v.GetSizeDim(0);i++)
   {
      SetElement(v.GetElement(i),i,c);
   }
}

template<class T>
Matrix<T>::Matrix(Vector<T> v):TabND<T>(2,v.GetSizeDim(0),1)
{
*this=v;
}


template<class T>
Matrix<T> Matrix<T>::operator=(Vector<T> v)
{
for(long i=0;i<v.GetSizeDim(0);i++)
{
    SetElement(v.GetElement(i),i,0);
}
return *this;
}

}//end namespace FPTK

#endif